package com.miaoquan.mqapitbk.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * 线程池配置
 *
 * @author Fa
 * @date 2020-04-05 16:27
 */
@Slf4j
@Configuration
public class ExecutorPoolConfig {

    @Bean
    @ConditionalOnMissingBean
    public TraceThreadPoolExecutor executorService() {
        return new TraceThreadPoolExecutor(8, 8,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ThreadFactory() {
                    /* For autonumbering anonymous threads. */
                    private int threadInitNumber;

                    private synchronized int nextThreadNum() {
                        return threadInitNumber++;
                    }

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "ExecutorPool" + nextThreadNum());
                    }
                }
        );
    }

    public class TraceThreadPoolExecutor extends ThreadPoolExecutor {

        public TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }

        @Override
        public void execute(Runnable command) {
            super.execute(wrap(command, clientTrace(), Thread.currentThread().getName()));
        }

        @Override
        public Future<?> submit(Runnable task) {
            return super.submit(wrap(task, clientTrace(), Thread.currentThread().getName()));
        }

        private Exception clientTrace() {
            return new Exception("client stack trace");
        }

        private Runnable wrap(final Runnable task, final Exception clientStack, String clientThreadName) {
            return () -> {
                try {
                    task.run();
                } catch (Exception e) {
                    log.error("线程名：" + clientThreadName + "，原因：" + e.getMessage(), e);
//                    throw e;
                }
            };
        }
    }

}
